@x-ninja 所感
!!!注意!!!
2020年に書かれた記事です
それからリリースは来てないので内容が古くなった訳ではないです
が、コミュニティからの見え方は大きく変わっている可能性が高いです
作者の言説は消しました
あまりにも不快なのと、前よりも悪化しているので…
ここには乗せませんし正直本当に酷いので見るべきではないです
どうしても見るというのであれば止めません
(悪い意味で)噂の JS フレームワークがついに登場!
一生リリースされないと思っていた Ma_gician が @x-ninja に名を変えて(?)リリースされていたので触ってみました。
なお @x-ninja 本体はビルド済みコードが npm やらにあるだけでソースコードは公開されていません。一応 MIT ライセンスらしいけど… といってもダラダラ書いてしまうとただのドキュメントの焼き鈍しになってしまうので、気になった部分だけ…
脱線: width に 100vw を指定するな
@x-ninja の公式ホームページだけに限らず width に 100vw が指定されているウェブページはよくありますが、100vw には縦方向スクロールバーの幅が含まれていません。
とくに Firefox だとウェブページのサイズが画面からはみ出て横方向のスクロールバーが出るのでやめてください。
利用方法
よしなに o_o.js と flux._.js を script タグで読み込めば良いらしいです。
どういう命名なのかは分かりません、flux._.js に至っては中身が空だし…
code: import.html
なお各種ロジックは HTML タグの属性値に書くため、**エディタの補完は全く効きません**。
アクティベート
React における ReactDOM.render() や Vue.js における new Vue() のように、@x-ninja にも _ というアクティベータ(Activator) があります。
アクティベータを置いた要素以下でしか @x-ninja の機能が使えません。
code:activator.html
<div _>
<!-- ↑これ -->
</div>
JS からもアクティベート出来るそうです。(が JS からアクティベートしたいケースが思い浮かばない…)
code:activator.js
const targetElement = document.getElementById('app')
targetElement._
Template と Flux
@x-ninja には Template と Flux という2種類の概念?があります。
が、2つの違いは状態管理が使えるか使えないかだけっぽそうです。
Flux では x-invocations ディレクティブで動的に状態を操作できますが、Template にはそのような機能が備わっていません。
そのため Template では名前の通り静的なウェブサイトを生成するテンプレートエンジンにしかならないので、用途が限られます。
Template のみを使うケースが思いつかなかったので、今回は Flux メインで使用します。
状態管理
上記の通り、Template と Flux のどちらでも状態を持つ事はできます。
Template では x-flush、Flux では x-controller で状態管理を有効にします。
code:state.html
<div x-flush></div>
<!-- or -->
<div x-controller></div>
初期状態
初期状態は Template では x-flush="{}"、Flux では x-state="{}" で定義します。が、Flux で x-flush="{}" を使っても問題ありませんでした。
ドキュメントを読む限りでは初期状態は JSON しか書けないように見えますが、実際は JS として解釈されるので { today: new Date().toISOString() } のように書けます。
code:initial-state.html
<div x-flush="{ text: 'Hoge' }">
{{ text }}
</div>
<!-- or -->
<div x-controller x-state="{ text: 'Hoge' }">
{{ text }}
</div>
状態を埋め込む
テキストとして埋め込む場合は {{ Text }} 構文か x-text ディレクティブを使います。
他にも
HTML として埋め込まれる {{{ HTML }}} 構文 (x-html ディレクティブ)
class と style 以外の属性に埋め込める x-bind:<attributes> ディレクティブ(値をそのまま渡すか、値の中で {{ Text }} で値を埋め込む)
値で class のオンオフが出来る x-bind:class ディレクティブ(使いづらい…)
lowerCamelCase と kebab-case で style を書ける x-bind:style ディレクティブ
があります。
なお値は JS として評価されるので {{ "Hoge" }} みたいに書くことも出来ます。
x-bind:class が動的に class を追加できない(定義済みの class をオンオフするだけ)のがキツそうですね…
model
v-model のような双方向バインディングも x-model ディレクティブで使えます。
code:model.html
<div x-controller>
<input
x-model="text"
value="hi"
<div>Text: {{ text }}</div>
</div>
method
Vue.js でいう method は x-invocations ディレクティブで定義できます。
code:method.html
<div x-invocations="{
hi (_, payload, meta) {
window.alert(payload.message)
},
}">
<button x-on:click="hi({ message: 'Hello'})">Hi</button>
</div>
算出プロパティ
Vue.js のような算出プロパティを x-computed={} で定義できます。
状態が this に束縛されるので、適当な式を getter として定義します。
code:computed.html
<div x-flush="{ today: new Date() }" x-computed="{
get date() {
return new Date(this.today).getDate()
}
}">
{{ date }}
</div>
ヘルパー?
テンプレートエンジンでよくあるヘルパーのような事を x-filters ディレクティブで実現できます。
code:filters.html
<div x-flush="{ hoge: 'Hello' }" x-filters="{
upper(text) {
return text.toUpperCase()
}
}">
{{ hoge |> upper }} <!-- HELLO -->
{{ "world" |> upper }} <!-- WORLD -->
</div>
制御構文
x-case で if、x-else で else、x-when で else if、x-each で foreach が使えます。
x-each は**自身ではなく子の要素**が繰り返し対象になります。
x-each="item, index in items" のように index を貰う事もできます。
code:control.html
<div x-case="hoge === 'piyo'">piyo</div>
<div x-when="hoge === 123">123</div>
<div x-else>another...</div>
<div x-each="book, index in books">
<p>{{ index }}: {{ book }}</p>
</div>
使ってみて
JS の記述量を減らした Vue.js のような感じでした。
とにかく JS を書くときに補完が効かないのがキツく、作者の意向もあってか2020年に登場したフレームワークなのに TypeScript 対応もありません。
しかし script タグで読み込めば JS をダラダラ書かなくても動的なウェブサイトを作れるというのは特定用途ではウケるんじゃないかなと思いました。
とまあライブラリとしては悪くはないと思いますが、とにかく開発の方針などの点が厳しいです。
最初に書いた通り、ソースコードは公開されていませんし、バグトラッカーなどもありません。
閉鎖的な開発が悪いとは言いませんが、得体の知れないフレームワークで多くのユーザーを集めるのは厳しいと思います。
しかも開発者が TypeScript (というか型付け言語全体?)を毛嫌いしており、2020年にもなって型の恩恵を得る事ができません。
まとめ
Vue.js で良いと思います。